Functional Programming

연습문제 2.2

Array[A]가 주어진 비교 함수에 의거해서 정렬되어 있는지 점검하는 isSorted함수를 구현하라. 서명은 다음과 같다.

def isSorted[A](as: Array[A], ordered: (A,A) => Boolean): Boolean

In [1]:
def isSorted[A](as: Array[A], ordered: (A, A) => Boolean): Boolean = {
    def loop(n: Int): Boolean =
        if (n == as.length -1) true
        else if (ordered(as(n), as(n+1))) loop(n+1)
        else false
    loop(0)
}


Out[1]:
defined function isSorted

In [2]:
def bigger(a: Int, b: Int): Boolean = 
    a < b


Out[2]:
defined function bigger

In [3]:
isSorted(Array(1, 3, 2), bigger)


Out[3]:
res2: Boolean = false

익명 함수, 함수 리터럴

고차 함수를 호출할 때, 함수를 정의후에 호출하는 것보다 익명 함수를 사용하여 호출하는 것이 편리한 경우가 많음.

'=>' 왼쪽에 괄호안에 파라미터 정의를, '=>' 오른쪽에 함수 본문을 작성


In [4]:
// 입력값이 9와 같은지 검사하는 익명함수
(x: Int) => x == 9  // REPL에서 결과로 함수 타입과 함께
                    // = 우측에 <function1> 으로 함수의 인수 갯수를 나타냄


Out[4]:
res3: Int => Boolean = <function1>

In [5]:
(a: Int, b: Int) => a == b


Out[5]:
res4: (Int, Int) => Boolean = <function2>

In [6]:
isSorted(Array(7,3,2,1), (a: Int, b: Int) => a > b)


Out[6]:
res5: Boolean = true

형식에서 도출된 구현

형식이 추상화 되면 구현 방법이 제한됨. Int에 대한 작업은 +, *, 제곱 등 다양한 연산들을 할 수 있지만, 임의의 타입 A에 대해서는 할 수 있는 작업이 제한되기 때문에 형식으로 부터 특정한 구현을 도출할 수 있음.

def partial1[A,B,C](a: A, f: (A, B) => C): B => C

In [7]:
def partial1[A,B,C](a: A, f: (A, B) => C): B => C =
    (b: B) => f(a, b)
// 아래의 구현은 같은 스칼라의 타입추론을 이용하여 조금더 간략화한 버전
def partial1_[A,B,C](a: A, f: (A, B) => C): B => C =
    f(a, _)


Out[7]:
defined function partial1
defined function partial1_

연습문제 2.3

또 다른 예로, 인수가 두 개인 함수 f를 인수 하나를 받고 그것으로 f를 부분 적용하는 함수로 변환하는 커링(currying)을 살펴보자. 이번에도 컴파일 되는 구현은 단 한 가지이다. 그러한 구현을 작성하라.

def curry[A,B,C](f: (A, B) => C): A => (B => C)

In [8]:
def curry[A,B,C](f: (A, B) => C): A => (B => C) = {
    (a: A) => (b: B) => f(a, b)
}
// 아래의 구현은 같은 스칼라의 타입추론을 이용하여 조금더 간략화한 버전
def curry2[A,B,C](f: (A, B) => C): A => (B => C) = {
    (a: A) => f(a, _: B) 
}
def curry3[A,B,C](f: (A, B) => C): A => (B => C) = {
    a => f(a, _: B)
}


Out[8]:
defined function curry
defined function curry2
defined function curry3

연습문제 2.4

curry의 변환을 역으로 수행하는 고차 함수 uncurry를 구현하라. =>는 오른쪽으로 묶이므로, A => (B => C)를 A => B => C라고 표기할 수 있음을 주의할 것.

def uncurry[A,B,C](f: A => B => C): (A, B) => C

In [9]:
def uncurry[A,B,C](f: A => B => C): (A, B) => C =
    (a: A, b: B) => f(a)(b)

// 아래의 구현은 같은 타입추론을 이용하여 조금더 간략화한 버전
def uncurry2[A,B,C](f: A => B => C): (A, B) => C =
    (a, b) => f(a)(b)
def uncurry3[A,B,C](f: A => B => C): (A, B) => C =
    f(_: A)(_: B)


Out[9]:
defined function uncurry
defined function uncurry2
defined function uncurry3

연습문제 2.5

두 함수를 합성하는 고차 함수를 구현하라.

def compose[A,B,C](f: B => C, g: A => B): A => C

In [10]:
def compose[A,B,C](f: B => C, g: A => B): A => C =
    (a: A) => f(g(a))
// 아래의 구현은 같은 타입추론을 이용하여 조금더 간략화한 버전
def compose2[A,B,C](f: B => C, g: A => B): A => C =
    (a) => f(g(a))


Out[10]:
defined function compose
defined function compose2

In [ ]: